package edu.iscas.xcheck.analysis.dom.checker;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import edu.iscas.xcheck.analysis.dom.model.BrowserEvent;
import edu.iscas.xcheck.analysis.dom.model.BrowserModel;
import edu.iscas.xcheck.analysis.dom.model.BrowserPage;
import edu.iscas.xcheck.analysis.dom.model.PageLog;
import edu.iscas.xcheck.analysis.model.XbiIssue;
import edu.iscas.xcheck.analysis.model.StateIssue;
import edu.iscas.xcheck.analysis.model.XbiIssue.ISSUETYPE;
import edu.iscas.xcheck.analysis.model.XbiIssue.XBITYPE;

public class IsoChecker {

	private BrowserModel model1, model2;
	private XBIResult results;

	public IsoChecker(BrowserModel model1, BrowserModel model2) {
		this.model1 = model1;
		this.model2 = model2;
		this.results = new XBIResult();
	}
	
	public void checkPages() {
		List<BrowserPage> browserPages1 = model1.getBrowserPages();
		List<BrowserPage> browserPages2 = model2.getBrowserPages();
		
		List<String> behaviorIssues = new ArrayList<String>();
		
		int i = 0;
		for (; i < browserPages1.size() && i < browserPages2.size(); i++) {
			long start = new Date().getTime();
			BrowserPage browserPage1 = browserPages1.get(i);
			BrowserPage browserPage2 = browserPages2.get(i);
			if (browserPage1.getUrl() != null
					&& browserPage1.getUrl().equals(browserPage2.getUrl())) {
				PageChecker pageChecker = new PageChecker(browserPage1,
						browserPage2, results);
				pageChecker.doCheck();
			} else {
				String issueMsg = formatIssuseString("MISSMATCH-PAGES",
						"page-" + i, browserPage1.getUrl(),
						browserPage2.getUrl());
				addIssue(XBITYPE.Behavior, ISSUETYPE.Different, issueMsg, browserPage1, browserPage2);
				behaviorIssues.add(issueMsg);
			}
			System.out.println("page-"+i+":"+(new Date().getTime()-start));
		}
		// collect miss page
		int j = i;
		for (; j < browserPages1.size(); j++) {
			BrowserPage browserLog1 = browserPages1.get(i);
			String issueMsg = formatIssuseString("MISS-PAGES", "page-" + j,
					browserLog1.getUrl(), null);
			addIssue(XBITYPE.Behavior, ISSUETYPE.Missing, issueMsg, browserLog1, null);
			behaviorIssues.add(issueMsg);
		}
		j = i;
		for (; j < browserPages2.size(); j++) {
			BrowserPage browserLog2 = browserPages2.get(i);
			
			String issueMsg = formatIssuseString("MISS-PAGES", null, "page-"
					+ j, browserLog2.getUrl());
			addIssue(XBITYPE.Behavior, ISSUETYPE.Additional, issueMsg, null, browserLog2);
			behaviorIssues.add(issueMsg);
		}
		this.results.addBehaviorIssues(behaviorIssues);
	}
	private XbiIssue addIssue(XBITYPE type, ISSUETYPE issue, String msg, BrowserPage browserPage1, BrowserPage browserPage2){
		List<BrowserEvent> event1 = null, event2 = null;
		if(browserPage1 != null && browserPage1.getLog() != null){
			event1 = browserPage1.getLog().getEvents();
		}
		if(browserPage2 != null && browserPage2.getLog() != null){
			event2 = browserPage2.getLog().getEvents();
		}
		return addIssue(type, issue, msg, event1, event2);
	}
	
	private XbiIssue addIssue(XBITYPE type, ISSUETYPE issue, String msg, List<BrowserEvent> eventList1, List<BrowserEvent> eventList2) {
		return addIssue(type, issue, msg,getLoadEvent(eventList1), getLoadEvent(eventList2));
	}
	
	private XbiIssue addIssue(XBITYPE type, ISSUETYPE issue, String msg, BrowserEvent event1, BrowserEvent event2) {
		int state = -1;
		String refImage = "", testImage = "";
		if(event2 != null){
			state = event2.getState();
			testImage = event2.getImage();
		}
		if(event1 != null){
			state = event1.getState();
			refImage = event1.getImage();
		}
		return addIssue(type, issue, msg, state, refImage, testImage);
	}
	
	private BrowserEvent getLoadEvent(List<BrowserEvent> eventList){
		if(eventList == null) return null;
		for(BrowserEvent event:eventList){
			if(event.getType().equals("load")){
				return event;
			}
		}
		return null;
	}
	
	private XbiIssue addIssue(XBITYPE type, ISSUETYPE issue, String msg, int state, String refImage, String testImage){
		StateIssue stateIssue = results.getStateIssues().get(state);
		if(stateIssue == null){
			stateIssue = new StateIssue(state, refImage, testImage);
			results.getStateIssues().put(state, stateIssue);
		}
		XbiIssue xbiIssue = new XbiIssue(type, issue, msg);
		stateIssue.addIssue(xbiIssue);
		return xbiIssue;
	}
	public XBIResult getResults() {
		return this.results;
	}

	private String formatIssuseString(String msg, String eventId, String node1,
			String node2) {
		return String.format("\"%s\",\"%s\",\"%s\",\"%s\"", msg, eventId,
				node1, node2);
	}
}
